/*******************************************************************************
 * @note Copyright (C) 2011-2022, Shanghai Panchip Microelectronics Co., Ltd. 
 * @SPDX-License-Identifier: Apache-2.0
 * @history - V0.1, 2022-09-28
*******************************************************************************/
#include "hal_pwm.h"
#include "hardware.h"

uint16_t RedValue   = 0;
uint16_t GreenValue = 0;
uint16_t BlueValue  = 0;

//软件PWM相关
//目前蓝灯是通过软件实现, 一共就10级调光, 越高要求的定时器频率也就越高, 否则会闪烁
#define RGB_BLUE_PORT		GpioPortB
#define RGB_BLUE_PIN		GpioPin6

uint8_t PwmPreiod = 10;				//周期=定时器时长*PwmPreiod
uint8_t PwmCurPreiodCnt = 0;		//当前周期计数
uint8_t PwmPreiodPulseBlue = 0;		//决定蓝灯的占空比, 最大为 PwmPreiod

//软件PWM处理函数, 在定时器中定时调用, 频率最好5K以上
void PWM_SW_Handle(void)
{
	if(PwmCurPreiodCnt <= PwmPreiod)//周期
	{   
		if(PwmCurPreiodCnt < PwmPreiodPulseBlue)//蓝灯占空比
		{      
			//IO拉高
			//Gpio_WriteOutputIO(RGB_BLUE_PORT, RGB_BLUE_PIN, 1);
			*((volatile uint32_t *)((uint32_t)&M0P_GPIO->PAOUT + RGB_BLUE_PORT)) |= (1<<RGB_BLUE_PIN);
 
		}
		else
		{
			//IO拉低
			//Gpio_WriteOutputIO(RGB_BLUE_PORT, RGB_BLUE_PIN, 0);
			*((volatile uint32_t *)((uint32_t)&M0P_GPIO->PAOUT + RGB_BLUE_PORT)) &= (~(1<<RGB_BLUE_PIN));
		}   
	
		if(PwmCurPreiodCnt == PwmPreiod)//累加到一个周期就清零
		{
			PwmCurPreiodCnt=0; 
		}
		else
		{
			PwmCurPreiodCnt++;//如果一个周期还没到继续累加
		}
	}
	else//超过一个周期也清零
	{
		PwmCurPreiodCnt=0;  
	}
}


//设置RGB颜色
//上层不需要关心是否是如何实现
//格式 0x00000000	0x00RRGGBB
void PWM_Set_RGB(uint32_t Value)
{
	//硬件
	RedValue   = ((Value>>16) & 0x000000ff);
	GreenValue = ((Value>>8)  & 0x000000ff);
//	BlueValue  = ( Value      & 0x000000ff);
	
	//软件
	PwmPreiodPulseBlue = ( Value      & 0x000000ff) /(255/PwmPreiod);
}

//定时器3中断
void Tim3_IRQHandler(void)
{
    //Timer3 模式23 更新中断
    if(TRUE == Tim3_GetIntFlag(Tim3UevIrq))
    {	
		Tim3_M23_CCR_Set(Tim3CCR0B, RedValue*15);		//设置CH  通道 比较值
		Tim3_M23_CCR_Set(Tim3CCR0A, GreenValue*15);		//设置CH  通道 比较值
		
		//Tim3_M23_CCR_Set(Tim3CCR0B, BlueValue*15); 		//设置CH  通道 比较值
		
		DBG_P1_FLIP();	
		
		//清中断标志
        Tim3_ClearIntFlag(Tim3UevIrq);  
		PWM_SW_Handle();
    }
}


//Timer3 Port端口配置
void Tim3_Timer3PortCfg(void)
{
    stc_gpio_cfg_t               stcTIM3Port;
    stc_gpio_cfg_t               stcLEDPort;
    
    //结构体初始化清零
    DDL_ZERO_STRUCT(stcTIM3Port);
    DDL_ZERO_STRUCT(stcLEDPort);
    
    Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE); //端口外设时钟使能
    
    stcTIM3Port.enDir  = GpioDirOut;
    
	//RGB-G		TIM3_CH0A
    Gpio_Init(GpioPortB, GpioPin3, &stcTIM3Port);           //PB3设置为
    Gpio_SetAfMode(GpioPortB,GpioPin3,GpioAf4);				//复用功能设置
    
	//RGB-R		TIM3_CH0B
    Gpio_Init(GpioPortB, GpioPin4, &stcTIM3Port);           //PB4设置为
    Gpio_SetAfMode(GpioPortB,GpioPin4,GpioAf6);				//复用功能设置
    
    Gpio_Init(GpioPortB, GpioPin6, &stcTIM3Port);			//PB6 目前不能使用硬件PWM
//    Gpio_SetAfMode(GpioPortB,GpioPin6,GpioAf6);				//
	Gpio_WriteOutputIO(GpioPortB, GpioPin6, 0);
}

//Timer3 配置
void Tim3_Timer3Cfg(uint16_t u16Period, uint16_t u16CHxBCompare)
{
    uint16_t                     u16CntValue;
    uint8_t                      u8ValidPeriod;
    stc_tim3_mode23_cfg_t        stcTim3BaseCfg;
    stc_tim3_m23_compare_cfg_t   stcTim3PortCmpCfg;
    
    //结构体初始化清零
    DDL_ZERO_STRUCT(stcTim3BaseCfg);
    DDL_ZERO_STRUCT(stcTim3PortCmpCfg);

    Sysctrl_SetPeripheralGate(SysctrlPeripheralTim3, TRUE);   	//Timer3外设时钟使能
        
    stcTim3BaseCfg.enWorkMode    = Tim3WorkMode3;             	//三角波模式
    stcTim3BaseCfg.enCT          = Tim3Timer;                 	//定时器功能，计数时钟为内部PCLK
    stcTim3BaseCfg.enPRS         = Tim3PCLKDiv1;              	//PCLK
    stcTim3BaseCfg.enCntDir    	 = Tim3CntUp;                 	//向上计数，在三角波模式时只读
    stcTim3BaseCfg.enPWMTypeSel  = Tim3IndependentPWM;        	//独立输出PWM    //Tim3ComplementaryPWM;
    stcTim3BaseCfg.enPWM2sSel    = Tim3SinglePointCmp;        	//单点比较功能
    stcTim3BaseCfg.bOneShot      = FALSE;                     	//循环计数
    stcTim3BaseCfg.bURSSel       = FALSE;                     	//上下溢更新
    
    Tim3_Mode23_Init(&stcTim3BaseCfg);                        	//TIM3 的模式23功能初始化
    
    Tim3_M23_ARRSet(u16Period, TRUE);                         	//设置重载值,并使能缓存
    
    Tim3_M23_CCR_Set(Tim3CCR0B, u16CHxBCompare);            	//设置CH0比较值B
    Tim3_M23_CCR_Set(Tim3CCR1B, u16CHxBCompare);            	//设置CH1比较值B
    Tim3_M23_CCR_Set(Tim3CCR2B, u16CHxBCompare);            	//设置CH2比较值B
    
    stcTim3PortCmpCfg.enCHxACmpCtrl   = Tim3PWMMode2;         	//OCREFA输出控制OCMA:PWM模式2
    stcTim3PortCmpCfg.enCHxAPolarity  = Tim3PortOpposite;     	//正常输出 Tim3PortPositive	 反向输出 Tim3PortOpposite
    stcTim3PortCmpCfg.bCHxACmpBufEn   = TRUE;                	//A通道缓存控制
    stcTim3PortCmpCfg.enCHxACmpIntSel = Tim3CmpIntNone;       	//A通道比较中断控制:无
    
    stcTim3PortCmpCfg.enCHxBCmpCtrl   = Tim3PWMMode2;         	//OCREFB输出控制OCMB:PWM模式2(PWM互补模式下也要设置，避免强制输出)
    stcTim3PortCmpCfg.enCHxBPolarity  = Tim3PortOpposite;     	//正常输出	//Tim3PortOpposite
    stcTim3PortCmpCfg.bCHxBCmpBufEn   = TRUE;                 	//B通道缓存控制使能
    stcTim3PortCmpCfg.enCHxBCmpIntSel = Tim3CmpIntNone;       	//B通道比较中断控制:无
    
    Tim3_M23_PortOutput_Cfg(Tim3CH0, &stcTim3PortCmpCfg);  		//比较输出端口配置
//    Tim3_M23_PortOutput_Cfg(Tim3CH1, &stcTim3PortCmpCfg);  		//比较输出端口配置
//    Tim3_M23_PortOutput_Cfg(Tim3CH2, &stcTim3PortCmpCfg);  		//比较输出端口配置
    
    u8ValidPeriod = 1;                                        	//事件更新周期设置，0表示三角波每半个周期更新一次，每+1代表延迟半个周期
    Tim3_M23_SetValidPeriod(u8ValidPeriod);                   	//间隔周期设置
    
    u16CntValue = 0;
    Tim3_M23_Cnt16Set(u16CntValue);                           	//设置计数初值
    
    Tim3_ClearAllIntFlag();                                   	//清中断标志
    Tim3_Mode23_EnableIrq(Tim3UevIrq);                        	//使能TIM3 UEV更新中断
    EnableNvic(TIM3_IRQn, IrqLevel0, TRUE);                   	//TIM3中断使能
}

//初始胡PWM
void Hal_Pwm_Init(void)
{
	PWM_Set_RGB(0x000000);						//初始化数值
	Tim3_Timer3PortCfg();                       //Timer3 Port端口配置
    Tim3_Timer3Cfg(3825, 3825);     			//Timer3 配置:周期 3825; CH0/1/2通道B比较值 3825
    Tim3_M23_EnPWM_Output(TRUE, FALSE);         //端口输出使能
    Tim3_M23_Run();                             //运行
}

